package com.essence.grabiec104.grab.router.request;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.*;
import com.essence.common.model.BytesFrame;
import com.essence.common.model.Packet;
import com.essence.common.model.Point;
import com.essence.common.model.Substation;
import com.essence.grabiec104.grab.dao.AlarmDao;
import com.essence.grabiec104.grab.dao.GrabberDao;
import com.essence.grabiec104.grab.model.*;
import com.essence.grabiec104.grab.router.Router;
import com.essence.grabiec104.grab.router.RouterComponent;
import com.essence.grabiec104.grab.service.AlarmService;
import com.essence.grabiec104.grab.service.GrabberService;
import com.essence.starter.model.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ResourceLoader;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RouterComponent
public class RouterQuery {
    @Autowired
    private GrabberDao grabDao;
    @Autowired
    private AlarmDao alarmDao;
    @Autowired
    private AlarmService alarmService;
    @Autowired
    private GrabberService grabService;

    @Autowired
    private ResourceLoader resourceLoader;

    @Router("login")
    public String login(LoginQuery query) {
        if (query.getUsername().equals("admin") && query.getPassword().equals("admin")) {
            return "success";
        }
        return "error";
    }

    @Router("select-frames")
    public List<BytesFrame> selectFrames(SelectFramesParams query) {
        List<BytesFrame> bytesFrames = grabDao.selectFrame(query.getSrcHost(),
                query.getDstHost(), query.getStartTime(), query.getEndTime(),
                query.getLimit(), query.getOffset());
        return bytesFrames;
    }

    @Router("select-point-info")
    public Page<PointInfo> selectPointInfo(SelectFramesParams params) {
        log.info("selectPointInfo: {}", params);
        Page<PointInfo> pointInfos = grabService.selectPointInfo(params);
        for (PointInfo pointInfo : pointInfos.getData()) {
            Packet.TieIdentificationEnum tieIdentificationEnum = Packet.TieIdentificationEnum.fromValue(pointInfo.getTieIdentification());
            pointInfo.setTieIdentificationDesc(tieIdentificationEnum.getDescription());
            Packet.CauseEnum causeEnum = Packet.CauseEnum.fromCode(pointInfo.getCause());
            pointInfo.setCauseDesc(causeEnum.getDescription());
        }
        return pointInfos;
    }

    @Router("select-all-substation")
    public List<Substation> getAllSubstation(String param) {
        return alarmService.getAllSubstation();
    }

    @Router("add-substation")
    public Substation addSubstation(Substation substation) {
        alarmService.addSubstation(substation);
        return substation;
    }

    @Router("update-substation")
    public int updateSubstation(Substation substation) {
        return alarmService.updateSubstation(substation);
    }

    @Router("delete-substation")
    public long deleteSubstation(Substation substation) {
        return alarmService.deleteSubstation(substation);
    }

    @Router("update-alarm-rules")
    public String updateAlarmRules(List<AlarmRuleQuery> queries) {
        alarmService.updateAlarmRules(queries);
        return "success";
    }

    @Router("get-alarm-rules")
    public List<AlarmRuleQuery> getAlarmRules(String stateId) {
        List<AlarmRuleQuery> alarmRuleQueries = alarmDao.selectAlarmRulesByStateId(Long.parseLong(stateId));
        return alarmRuleQueries;
    }

    @Router("get-alarm-record")
    public List<AlarmRecord> getAlarmRecord(String limit) {

        List<AlarmRecord> alarmRecords = alarmDao.selectAlarmRecord(Integer.parseInt(limit), 0);
        return alarmRecords;
    }

    @Router("generate-report")
    public String generateReport(SelectFramesParams query) throws IOException {
        Page<PointInfo> pointInfos = grabService.selectPointInfo(query);
        List<PointInfo> data = pointInfos.getData();
        for (PointInfo pointInfo : data) {
            Packet.TieIdentificationEnum tieIdentificationEnum = Packet.TieIdentificationEnum.fromValue(pointInfo.getTieIdentification());
            pointInfo.setTieIdentificationDesc(tieIdentificationEnum.getDescription());
            Packet.CauseEnum causeEnum = Packet.CauseEnum.fromCode(pointInfo.getCause());
            pointInfo.setCauseDesc(causeEnum.getDescription());
        }

        Map<String, Long> tiCount = data.stream().collect(Collectors.groupingBy(PointInfo::getTieIdentificationDesc, Collectors.counting()));
        RowRenderData countTableHeader = Rows.of("分项名称", "数据").bgColor("4472C4").textColor("FFFFFF").center().textBold().create();
        TableRenderData globalCountTable = Tables.create(countTableHeader);
        globalCountTable.addRow(Rows.create("总报文数量", String.valueOf(data.size())));
        for (Map.Entry<String, Long> entry : tiCount.entrySet()) {
            globalCountTable.addRow(Rows.create(entry.getKey(), String.valueOf(entry.getValue())));
        }

        HashSet<String> rtuList = new HashSet<>();
        RowRenderData row0 = Rows.of("时间", "源地址", "目标地址", "方向", "类型标识符", "目标点号", "点号描述", "目标值", "数据平面").bgColor("4472C4").textColor("FFFFFF").center().textBold().create();
        TableRenderData allTable = Tables.create(row0);
        for (PointInfo p : data) {
            allTable.addRow(Rows.of(DateUtil.format(new Date(p.getTimestamp()), "yyyy-MM-dd HH:mm:ss"),
                    p.getSrcName(),
                    p.getDstName(),
                    p.getDirection().equals("Upstream") ? "上行" : "下行",
                    p.getTieIdentification() + "-" + p.getTieIdentificationDesc(),
                    String.valueOf(p.getPointAddress()),
                    p.getPointDesc(),
                    p.getTieIdentification() == 45 ? (p.getPointValue() == 0 ? "分" : "合") : String.valueOf(p.getPointValue()),
                    p.getDataPlane()).create());
            rtuList.add(p.getDirection().equals("Upstream") ? p.getSrcHost() : p.getDstHost());
        }
        List<Substation> allSubstation = alarmDao.getAllSubstation();
        List<Substation> rtus = new ArrayList<>();
        for (Substation substation : allSubstation) {
            if (substation.isRtu()) {
                for (String s : rtuList) {
                    if (s.equals(substation.getHost())) {
                        rtus.add(substation);
                    }
                }
            }
        }

        Map<String, Object> templateMap = new HashMap<>();
        templateMap.put("allTable", allTable);
        templateMap.put("globalCountTable", globalCountTable);
        templateMap.put("rtuSize", rtuList.size());

        //分站统计
        RowRenderData header = Rows.of("子站名称", "IP地址", "端口").bgColor("4472C4").textColor("FFFFFF").center().textBold().create();
        TableRenderData rtuTable = Tables.create(header);
        RowRenderData rtuCountTableHeader = Rows.of("子站名称", "分项名称", "数据").bgColor("4472C4").textColor("FFFFFF").center().textBold().create();
        TableRenderData rtuCountTable = Tables.create(rtuCountTableHeader);
        for (Substation rtu : rtus) {
            List<PointInfo> rtuFrames = data.stream().filter(p -> p.getSrcHost().equals(rtu.getHost()) || p.getDstHost().equals(rtu.getHost())).collect(Collectors.toList());
            Map<String, Long> rtuTiCount = rtuFrames.stream()
                    .collect(Collectors.groupingBy(
                            PointInfo::getTieIdentificationDesc,
                            Collectors.counting()
                    ));
            rtuTable.addRow(Rows.create(rtu.getDescription(), rtu.getHost(), String.valueOf(rtu.getPort())));
            rtuCountTable.addRow(Rows.create(rtu.getDescription(), "总报文数量", String.valueOf(rtuFrames.size())));
            for (Map.Entry<String, Long> entry : rtuTiCount.entrySet()) {
                rtuCountTable.addRow(Rows.create("", entry.getKey(), String.valueOf(entry.getValue())));
            }
        }
        templateMap.put("rtuTable", rtuTable);
        templateMap.put("rtuCountTable", rtuCountTable);
        XWPFTemplate template = XWPFTemplate.compile(resourceLoader.getResource("classpath:templates/report.docx").getInputStream()).render(templateMap);

        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            template.write(out);  // 直接写入内存流
            byte[] bytes = out.toByteArray();
            return Base64.getEncoder().encodeToString(bytes);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Router("get-all-points")
    public List<Substation> getAllPoints(String param) {
        List<Substation> allSubstation = alarmDao.getAllSubstation();
        List<Point> points = alarmDao.selectAllPoint();
        allSubstation.stream().filter(Substation::isRtu).forEach(si -> si.setPoints(
                points.stream().filter(p -> p.getSubstationId() == si.getId()).collect(Collectors.toList())
        ));
        return allSubstation;
    }

    @Router("get-point-by-id")
    public Substation getPointById(long id) {
        Substation substation = alarmDao.getSubstationById(id);
        List<Point> points = alarmDao.selectPointBySubstationId(id);
        substation.setPoints(points);
        return substation;
    }

    @Router("save-correlation")
    public String saveCorrelation(List<CorrelationPointQuery> queries) {
        alarmService.saveCorrelation(queries);
        return "success";
    }

    @Router("control-instruction-number")
    public int controlInstructionNumber(String param) {
        return grabDao.controlInstructionNumber();
    }

    @Router("select-pointinfos-latest")
    public List<PointInfo> selectPointInfosLatest(int limit) {
        return grabService.selectPointInfosLatest(limit);
    }

    @Router("select-control-instruction-cycle")
    public CycleQuery selectControlInstructionCycle(int cycle) {
        CycleQuery query = alarmService.selectControlInstructionCycle(cycle);
        return query;
    }

    @Router("last-30days-instruction-count")
    public List<Integer> last30daysInstructionCount(String param) {
        return alarmService.last30daysInstructionCount();
    }

    @Router("set-point-filter")
    public String setPointFilter(List<Point> points) {
        grabService.setPointFilter(points);
        return "success";
    }

    @Router("set-point-relation")
    public String setPointRelation(List<CorrelationPointQuery> queries) {
        grabService.setPointRelation(queries);
        return "success";
    }

    @Router("select-yk-comparison")
    public YKComparison getYKComparison(YKComparison ykComparison) {
        List<YKComparison.YKComparisonItem> items0 = alarmService.selectYKComparison(ykComparison.getSlaveStations().get(0), ykComparison.getTimestamp());
        List<YKComparison.YKComparisonItem> items1 = alarmService.selectYKComparison(ykComparison.getSlaveStations().get(1), ykComparison.getTimestamp());

        ykComparison.getItemsGroupBy().put(ykComparison.getSlaveStations().get(0), items0);
        ykComparison.getItemsGroupBy().put(ykComparison.getSlaveStations().get(1), items1);
        return ykComparison;
    }

    @Router("generate-check-report")
    public String generateCheckReport(List<List<String>> table) throws IOException {

        int total = table.size() - 1;
        int same = 0;

        TableRenderData orderTable = Tables.create(Rows.of("比对结果", "目标对象", "D5000指令详情", "新一代指令详情")
                .bgColor("4472C4")
                .textColor("FFFFFF")
                .center()
                .textBold()
                .create());
        for (int i = 1; i < table.size(); i++) {
            List<String> row = table.get(i);
            if (row.get(1).equals("一致")) {
                same++;
                orderTable.addRow(Rows.create(row.get(1), row.get(2),
                        ("点号：" + row.get(4) + "\n方向：" + row.get(5) + "\n类型：" + row.get(9) + "\n值：" + row.get(8)),
                        ("点号：" + row.get(11) + "\n方向：" + row.get(12) + "\n类型：" + row.get(16) + "\n值：" + row.get(15))));
            } else {
                //不一致背景设置为红色
                orderTable.addRow(Rows.of(row.get(1), row.get(2),
                        ("点号：" + row.get(4) + "\n方向：" + row.get(5) + "\n类型：" + row.get(9) + "\n值：" + row.get(8)),
                        ("点号：" + row.get(11) + "\n方向：" + row.get(12) + "\n类型：" + row.get(16) + "\n值：" + row.get(15))).bgColor("F4CCCC").create());
            }
        }

        TableRenderData checkTable = Tables.create(Rows.of("统计项目", "数量", "备注")
                .bgColor("4472C4")
                .textColor("FFFFFF")
                .center()
                .textBold().
                        create());
        checkTable.addRow(Rows.create("总数量", String.valueOf(total), ""))
                .addRow(Rows.create("一致数量", String.valueOf(same), ""))
                .addRow(Rows.create("不一致数量", String.valueOf(total - same), ""));

        Map<String, Object> data = new HashMap<>();
        data.put("checkTable", checkTable);
        data.put("orderTable", orderTable);
        //当前时间往前推一个小时
        data.put("startTime", DateUtil.offset(DateUtil.parse(DateUtil.now()), DateField.HOUR, -1));
        data.put("endTime", DateUtil.now());
        XWPFTemplate template = XWPFTemplate.compile(resourceLoader.getResource("classpath:templates/check-report.docx").getInputStream()).render(data);
        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            template.write(out);
            byte[] bytes = out.toByteArray();
            return Base64.getEncoder().encodeToString(bytes);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Router("alarm-number")
    public String alarmNumber(String param) {
        return String.valueOf(alarmDao.sumAlarmRecord());
    }

    @Router("last-30days-alarm-count")
    public List<Integer> last30DaysAlarmCount(String param) {
        return alarmService.last30DaysAlarmCount();
    }
}
